#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "ohos_init.h"
#include "cmsis_os2.h"
#include <stdlib.h>
#include "hi_gpio.h"
#include "hi_io.h"
#include "hi_adc.h"
#include "hi_errno.h"
#include "math.h"
#include <errno.h>
#include "wifi_connecter.h"
#include "net_common.h"

#include "init.h"
#include "ssd1306/ssd1306.h"
#include "ssd1306/ssd1306_sdk.h"
#define SCOUNT 30              // TDS采样次数
#define host "175.178.100.193" // your PC IP address
#define stepPin 7              // 控制引脚
#define dirPin 8               // 方向引脚
#define MAX_TIMEOUTS 3         // udp发送请求最大超时重发次数

int state = 1;                // 水阀状态，0：关，1：开；
int water_id = 001;           // 水表ID
static char request[25] = ""; // 发送的消息
static char request1[2] = ""; // 发送的消息

static char response[128] = "";
static char response1[128] = "";
const int stepsPerRevolution = 51; // 电机转90°
int num = 0;                       // 水流量脉冲数
float analogBuffer[SCOUNT];        // 将从ADC读取的模拟值存储在数组中
int analogBuffer1[SCOUNT];         // 将从ADC读取的模拟值存储在数组中
float analogBufferTemp[SCOUNT];    // 盗版上一个数组
float analogBufferTemp1[SCOUNT];   // 盗版上一个数组
int analogBufferIndex = 0, analogBufferIndex1 = 0, copyIndex = 0, copyIndex1 = 0;
float averageVoltage = 0, tdsValue = 0, temperature0 = 25, temperature = 0; // 常温，待测温度
float p = 600.0;                                                            // 为1L水所需要的脉冲
float f;                                                                    // 实际水流量
float v;                                                                    // 流速
float Hydraulic;                                                            // 压力
int timeouts = 0;                                                           // 超时重发次数
int flage = 0;                                                              // 开始采样标记，1开始采样
int flage1 = 0;                                                             // 开始上传数据标志
float history_f;                                                            // 历史水流量
float date[20];                                                             // 需要传输的数据
char strArray[20][20];                                                      // 存储转换后的字符串数组

double MYLOG(double a) // 数学中的ln函数
{
    int N = 15; // 我们取了前15+1项来估算
    int k, nk;
    double x, xx, y;
    x = (a - 1) / (a + 1);
    xx = x * x;
    nk = 2 * N + 1;
    y = 1.0 / nk;
    for (k = N; k > 0; k--)
    {
        nk = nk - 2;
        y = 1.0 / nk + xx * y;
    }
    return 2.0 * x * y;
}

void Func() // 中断回调函数测水流量
{
    num++;
}

float getMedianNum(float bArray[], int iFilterLen) // ju值滤波算法
{
    float bTab[iFilterLen];
    for (int i = 0; i < iFilterLen; i++)
        bTab[i] = bArray[i];
    int i, j;
    float bTemp;
    for (j = 0; j < iFilterLen - 1; j++)
    {
        for (i = 0; i < iFilterLen - j - 1; i++)
        {
            if (bTab[i] > bTab[i + 1])
            {
                bTemp = bTab[i];
                bTab[i] = bTab[i + 1];
                bTab[i + 1] = bTemp;
            }
        }
    }
    if ((iFilterLen & 1) > 0)
    {
        bTemp = bTab[(iFilterLen - 1) / 2];
    }
    else
    {
        bTemp = (bTab[iFilterLen / 2] + bTab[iFilterLen / 2 - 1]) / 2;
    }

    return bTemp;
}

void Turn_Off()
{
    if (state == 1)
    {
        printf("now is turn off!\n");
        hi_gpio_set_ouput_val(dirPin, 1);
        for (int x = 0; x < stepsPerRevolution; x++)
        {
            hi_gpio_set_ouput_val(stepPin, 1);
            usleep(2000);
            hi_gpio_set_ouput_val(stepPin, 0);
            usleep(2000);
            // printf("now is step 1\n");
        }
        state = 0;
        printf("turn off down   state: %d\n", state);
    }

    // printf("Turn off down-_-\n");
}

void Turn_On()
{
    if (state == 0)
    {
        printf("now is turn on!\n");
        hi_gpio_set_ouput_val(dirPin, 0);
        for (int x = 0; x < stepsPerRevolution; x++)
        {
            hi_gpio_set_ouput_val(stepPin, 1);
            usleep(2000);
            hi_gpio_set_ouput_val(stepPin, 0);
            usleep(2000);
            // printf("now is step 1\n");
        }
        state = 1;
        printf("turn on down    state: %d\n", state);
    }
    // printf("Turn on down-_-\n");
}

static void UDP(void *arg)
{
    // 1.开wifi 配置要连接的wifi信息
    WifiDeviceConfig apConfig = {0};
    strcpy(apConfig.ssid, "Fsr");              // 设置wifi ssid "h" Set wifi ssid
    strcpy(apConfig.preSharedKey, "12345678"); // 设置wifi 密码 "12345678" Set wifi password
    apConfig.securityType = WIFI_SEC_TYPE_PSK;

    int netId = ConnectToHotspot(&apConfig); // 已完成连接
    usleep(2000000);

    //  2.建立UDP连接
    printf("UDP connecting\n");
    ssize_t retval = 0;
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0); // UDP socket
    struct sockaddr_in toAddr = {0};
    toAddr.sin_family = AF_INET;
    toAddr.sin_port = htons(4399); // 端口号，从主机字节序转为网络字节序

    // toAddr.sin_port = htons(4399); // 端口号，从主机字节序转为网络字节序
    // 设置接收超时时间
    struct timeval tv;
    tv.tv_sec = 5;
    tv.tv_usec = 0;
    if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    printf("connecting…………\n");

    // 连接， 将主机IP地址从“点分十进制”字符串 转化为 标准格式（32位整数）
    if (inet_pton(AF_INET, host, &toAddr.sin_addr) <= 0)
    {
        printf("inet_pton failed!\r\n");
    }
    printf("UDP already connect\n");
    request1[0] = 'h';
    request1[1] = '1';
    request1[2] = '\0';
    retval = sendto(sockfd, request1, sizeof(request1), 0, (struct sockaddr *)&toAddr, sizeof(toAddr));
    if (retval < 0)
    {
        printf("sendto failed!\r\n");
    }
    printf("send UDP message {%s} %ld done!\r\n", request1, retval);
    printf("Start to receive\n");
    struct sockaddr_in fromAddr1 = {0};
    socklen_t fromLen1 = sizeof(fromAddr1);
    retval = recvfrom(sockfd, &response1, sizeof(response1), 0, (struct sockaddr *)&fromAddr1, &fromLen1);
    //

    //
    printf("peer info: ipaddr = %s, port = %hu\r\n", inet_ntoa(fromAddr1.sin_addr), ntohs(fromAddr1.sin_port));
    if (retval <= 0)
    {
        printf("recvfrom failed or abort, %ld, %d!\r\n", retval, errno);
    }
    else
    {
        response1[retval] = '\0';
        printf("recv UDP message {%s} %ld done!\r\n", response1, retval);
        history_f = atof(response1);
        flage1 = 1;
        flage = 1;
    }

    if (flage1 == 1)
    {
        while (1)
        {
            // 3.上传数据
            sprintf(request, "%d_%.3f_%.3f_%.3f_%.3f", water_id, f + history_f, temperature, 200 * Hydraulic, tdsValue); // 水流量
            // printf("strlen:%d\n", strlen(request));
            // UDP socket 是 “无连接的” ，因此每次发送都必须先指定目标主机和端口，主机可以是多播地址
            retval = sendto(sockfd, request, sizeof(request), 0, (struct sockaddr *)&toAddr, sizeof(toAddr));
            if (retval < 0)
            {
                printf("sendto failed!\r\n");
            }
            printf("send UDP message {%s} %ld done!\r\n", request, retval);

            // 4.等待响应
            printf("Start to receive\n");
            retval = recvfrom(sockfd, &response1, sizeof(response1), 0, (struct sockaddr *)&fromAddr1, &fromLen1);
            printf("peer info: ipaddr = %s, port = %hu\r\n", inet_ntoa(fromAddr1.sin_addr), ntohs(fromAddr1.sin_port));
            if (retval <= 0)
            {
                printf("recvfrom failed or abort, %ld, %d!\r\n", retval, errno);
            }
            else
            {
                response1[retval] = '\0';

                printf("recv UDP message {%s} %ld done!\r\n", response1, retval);
                if (response1[0] == '1')
                {
                    printf("I am going to turn on\n");
                    if (state == 0)
                    {
                        hi_gpio_set_ouput_val(HI_GPIO_IDX_14, 1);
                        usleep(100);
                        Turn_On();
                    }
                    hi_gpio_set_ouput_val(HI_GPIO_IDX_14, 0);
                }
                if (response1[0] == '0')
                {
                    printf("I am going to turn off\n");
                    if (state == 1)
                    {
                        hi_gpio_set_ouput_val(HI_GPIO_IDX_14, 1);
                        usleep(100);
                        Turn_Off();
                    }
                    hi_gpio_set_ouput_val(HI_GPIO_IDX_14, 0);
                }
            }
            usleep(1000000);
        }
    }
}
static void UDP_receive(void *arg)
{
    (void)arg;
}

static void AdcGpioTask(void *arg)
{
    (void)arg;

    hi_u16 value;                      // 存温度的
    hi_u16 value1;                     // 存TDS的
    hi_u16 value2;                     // 存水压的
    const float thermistorR = 50000.0; // 温度传感器的分压电阻
    const float T0 = 298.15;           // 热敏电阻在25摄氏度下的温度，单位为开尔文
    const float B = 3950.0;            // 热敏电阻的B值
    float Vntc, Rntc;                  // 热敏电阻的电压、电阻
    float Vtemp;
    int average = 0, sum = 0;
    while (1)
    {
        printf("flage:%d\n", flage);
        usleep(2000000);
        if (flage == 1)
        {
            while (1)
            {
                // 1.测水流量
                printf("-----------start---------\n");
                hi_gpio_register_isr_function(HI_GPIO_IDX_4, HI_INT_TYPE_EDGE, HI_GPIO_EDGE_RISE_LEVEL_HIGH, Func, NULL); // 上升沿中断
                f = (float)num / p;                                                                                       // 用了多少升水
                printf("num:%d\n", num);
                printf("water : %fL\n", f + history_f); // 打印水流量
                Water_Ssd1306_Update(water_screen_water, f + history_f);
                usleep(100000);
                // 2.测温度
                if (hi_adc_read(HI_ADC_CHANNEL_0, &value, HI_ADC_EQU_MODEL_8, HI_ADC_CUR_BAIS_DEFAULT, 0) != HI_ERR_SUCCESS) // 读取引脚的模拟信号
                {
                    printf("ADC read error!\n");
                }
                else
                {
                    // 滤去尖波
                    // printf("value = %d\n", value);
                    // analogBuffer1[analogBufferIndex1] = value;
                    // analogBufferIndex1++;
                    // if (analogBufferIndex1 == SCOUNT)
                    // {
                    //     analogBufferIndex1 = 0;
                    // }
                    // for (copyIndex1 = 0; copyIndex1 < SCOUNT; copyIndex1++)
                    // {
                    //     analogBufferTemp1[copyIndex1] = analogBuffer1[copyIndex1];
                    // }
                    // average = getMedianNum(analogBufferTemp1, SCOUNT); // 通过中值滤波算法读取更稳定的模拟值，并转换为电压值
                    Vntc = ((float)value * 4 * 1.8) / 4096.0; // 将模拟量转换成实际电压值
                    // Vntc = Vntc + 1;
                    Vtemp = Vntc + 0.1;
                    Rntc = (thermistorR * Vtemp) / (5.0 - Vtemp); // 分压公式
                    printf("V = %f\n", Vntc);
                    printf("Vtemp = %f\n", Vtemp);
                    printf("R = %f\n", Rntc / 1000);
                    temperature = (1 / (MYLOG((double)Rntc / (double)thermistorR) / B + (1 / T0))) - 273.15; // 热敏电阻计算温度的固定公式
                    Water_Ssd1306_Update(water_screen_temp, temperature);
                    printf("temp = %.2f\n", temperature);
                    if (temperature >= 40)
                    {
                        hi_gpio_set_ouput_val(HI_GPIO_IDX_2, 1);
                    }
                    else
                    {
                        hi_gpio_set_ouput_val(HI_GPIO_IDX_2, 0);
                    }
                    usleep(100000);
                }

                // 3.测TDS
                if (hi_adc_read(HI_ADC_CHANNEL_4, &value1, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0) != HI_ERR_SUCCESS)
                {
                    printf("TDS read error!\n");
                }
                else
                {
                    // printf("value1:%d\n", value1);
                    analogBuffer[analogBufferIndex] = (value1 * 4 * 1.8) / 4096; // 转换成电压
                    // averageVoltage = ((float)value1 * 4 * 1.8) / 4096.0;
                    // printf("analogBuffer[%d]:%f\n", analogBufferIndex, analogBuffer[analogBufferIndex]);
                    analogBufferIndex++;
                    if (analogBufferIndex == SCOUNT)
                    {
                        analogBufferIndex = 0;
                    }
                    for (copyIndex = 0; copyIndex < SCOUNT; copyIndex++)
                    {
                        analogBufferTemp[copyIndex] = analogBuffer[copyIndex];
                    }
                    averageVoltage = getMedianNum(analogBufferTemp, SCOUNT); // 通过中值滤波算法读取更稳定的模拟值，并转换为电压值
                    // printf("TDS_averageV1:%.2f\n", ((float)value1 * 4 * 1.8) / 4096.0);
                    // averageVoltage = ((float)value1 * 4 * 1.8) / 4096.0;
                    printf("TDS_averageV2:%f\n", averageVoltage);
                    tdsValue = (133.42 * averageVoltage * averageVoltage * averageVoltage - 255.86 * averageVoltage * averageVoltage + 857.39 * averageVoltage) * 1.18;
                    // ECvalue25  =  ecvalue / (1.0+0.02*(temperature-25.0));
                    tdsValue = tdsValue / (1.0 + 0.02 * (22 - 25.0));
                    tdsValue = tdsValue / 2;
                    Water_Ssd1306_Update(water_screen_TDS, tdsValue);
                    printf("TDS:%.2fppm\n", tdsValue);
                    usleep(100000);
                }

                // 4.测水压
                if (hi_adc_read(HI_ADC_CHANNEL_2, &value2, HI_ADC_EQU_MODEL_4, HI_ADC_CUR_BAIS_DEFAULT, 0) != HI_ERR_SUCCESS)
                {
                    printf("Hydraulic read error!\n");
                }
                else
                {
                    Hydraulic = (value2 * 4 * 1.8) / 4096; // 转换成电压
                    // printf("value2:%f", Hydraulic);
                    Water_Ssd1306_Update(water_screen_Hydraulic, (200 * Hydraulic));
                    printf("Hydraulic:%.2fKpa\n", (200 * Hydraulic));
                    usleep(100000);
                }
                printf("-----------end---------\n");
                usleep(1000000);
            }
        }
    }
}

static void AdcGpioEntry(void)
{
    printf("ADC Test!\n");
    osThreadAttr_t attr;
    Water_TCP_GPIO_Init();
    Water_Ssd1306_Init();

    attr.name = "AdcGpioTask";
    attr.attr_bits = 0U;
    attr.cb_mem = NULL;
    attr.cb_size = 0U;
    attr.stack_mem = NULL;
    attr.stack_size = 30720;
    attr.priority = 25;

    if (osThreadNew(AdcGpioTask, NULL, &attr) == NULL)
    {
        printf("[LedExample] Falied to create LedTask!\n");
    }

    attr.name = "UDP";
    attr.priority = 25;
    if (osThreadNew(UDP, NULL, &attr) == NULL)
    {

        printf("[UDP] Falied to create LedTask!\n");
    }
}

SYS_RUN(AdcGpioEntry);